#include "MTime.h"
#ifdef Q_OS_WIN
    // windows系统
    #pragma comment(lib, "winmm.lib")
    #include <Windows.h>
    #include <MMSystem.h>
#elif defined(Q_OS_LINUX)
// linux系统 后续用到的时候再补充
#elif defined(Q_OS_MAC)
// mac系统 后续用到的时候再补充
#endif

QMutex _MDateTime_Mutex;

LARGE_INTEGER _MDateTime_litmp;
qint64 _MDateTime_PerformanceFrequency = (QueryPerformanceFrequency(&_MDateTime_litmp), _MDateTime_litmp.QuadPart);
qint64 _MDateTime_PerformanceStartCount= (QueryPerformanceCounter(&_MDateTime_litmp),   _MDateTime_litmp.QuadPart);


MTime::MTime() : QTime(), QPart1(0), m_ms(0) {}
MTime::MTime(int h, int m, int s, double ms) : QTime(h,m,s,ms), QPart1(0), m_ms(ms>=0&&ms<1000?ms:0) {}
MTime::MTime(const QTime &time) : QTime(time.hour(), time.minute(), time.second(), time.msec()), QPart1(0), m_ms(time.msec()) {}
MTime::MTime(const MTime &time) : QTime(time.hour(), time.minute(), time.second(), time.msec()), QPart1(0), m_ms(time.m_ms) {}


int MTime::usec()
{
    return m_ms*1000+0.5;
}

int MTime::nsec()
{
    return m_ms*1000000+0.5;
}

qint64 MTime::usecTo(const MTime &t)
{
    return (msecsTo(t) + (t.m_ms-int(t.m_ms)) - (m_ms-int(m_ms)) )*1000 + 0.5;
}

qint64 MTime::nsecTo(const MTime &t)
{
    return (msecsTo(t) + (t.m_ms-int(t.m_ms)) - (m_ms-int(m_ms)) )*1000000 + 0.5;
}

double MTime::getInteralMsVal()
{
    return m_ms;
}

QString MTime::toString(const QString &format) const
{
    QString rlt = QTime::toString(format);

    QRegExp reg("[uU]+");
    int pos = reg.indexIn(rlt,0);
    if( pos>=0 )
    {
        int len = reg.matchedLength();
        switch( len )
        {
        case 0: rlt.replace(pos, len, QString("%1").arg(int(m_ms*0.001+0.5), len, 10, QLatin1Char('0'))); break;
        case 1: rlt.replace(pos, len, QString("%1").arg(int(m_ms*0.01+0.5), len, 10, QLatin1Char('0'))); break;
        case 2: rlt.replace(pos, len, QString("%1").arg(int(m_ms*0.1+0.5), len, 10, QLatin1Char('0'))); break;
        case 3: rlt.replace(pos, len, QString("%1").arg(int(m_ms*1+0.5), len, 10, QLatin1Char('0'))); break;
        case 4: rlt.replace(pos, len, QString("%1").arg(int(m_ms*10+0.5), len, 10, QLatin1Char('0'))); break;
        case 5: rlt.replace(pos, len, QString("%1").arg(int(m_ms*100+0.5), len, 10, QLatin1Char('0'))); break;
        case 6: rlt.replace(pos, len, QString("%1").arg(int(m_ms*1000+0.5), len, 10, QLatin1Char('0'))); break;
        case 7: rlt.replace(pos, len, QString("%1").arg(int(m_ms*10000+0.5), len, 10, QLatin1Char('0'))); break;
        case 8: rlt.replace(pos, len, QString("%1").arg(int(m_ms*100000+0.5), len, 10, QLatin1Char('0'))); break;
        default:rlt.replace(pos, len, QString("%1").arg(int(m_ms*1000000+0.5), len, 10, QLatin1Char('0'))); break;
        }
    }
    return rlt;
}

void MTime::setHMS(int h, int m, int s, double ms)
{
    QTime::setHMS(h,m,s,ms);
    m_ms = ms>=0&&ms<1000?ms:0;
}

MTime MTime::addMSecs(double ms) const
{
    quint64 time = 1000 * (1000 * ( hour()*3600 + minute()*60 + second() ) + (m_ms + ms)*1000);
    quint64 spd = 86400000000000000;
    qint64 x = time % spd;
    if( x<0 ) x += spd;

    qint64 s1 = x/1000000000000;
    double s2 = x - s1*1000000000000;

    QTime baseTime(0,0,0);
    baseTime = baseTime.addSecs(s1);
    return MTime(baseTime.hour(), baseTime.minute(), baseTime.second(), s2/1e9);
}

MTime MTime::addSecs(int secs) const
{
    QTime baseTime = QTime::addSecs(secs);
    return MTime(baseTime.hour(), baseTime.minute(), baseTime.second(), m_ms );
}

void MTime::start()
{
    LARGE_INTEGER litmp;
    QueryPerformanceCounter(&litmp);
    QPart1 = litmp.QuadPart;
}

void MTime::restart()
{
    start();
}

double MTime::elapsed()
{
    LARGE_INTEGER litmp;
    QueryPerformanceCounter(&litmp);
    QMutexLocker locker(&_MDateTime_Mutex);
    return 1000.0*(litmp.QuadPart-QPart1) / _MDateTime_PerformanceFrequency;  //   λms
}

void MTime::sleep(double ms)
{
    LARGE_INTEGER litmp;
    QueryPerformanceCounter(&litmp);
    LONGLONG p1 = litmp.QuadPart;

    qint64 f;
    {
        QMutexLocker locker(&_MDateTime_Mutex);
        f = _MDateTime_PerformanceFrequency;
    }

    while( QueryPerformanceCounter(&litmp), 1000.0*( litmp.QuadPart - p1 ) / f  < ms);
}

bool MTime::operator !=( const MTime & t ) const
{
    return !(t.hour() == hour() && t.minute() == minute() && t.second() == second() && t.m_ms == m_ms );
}

bool MTime::operator<  ( const MTime & t ) const
{
    if(t.hour()>hour()) return true; else if(t.hour()<hour()) return false;
    if(t.minute()>minute()) return true; else if(t.minute()<minute()) return false;
    if(t.second()>second()) return true; else if(t.second()<second()) return false;
    if(t.m_ms>m_ms) return true; else if(t.m_ms<m_ms) return false;
    return false;
}

bool MTime::operator<= ( const MTime & t ) const
{
    if(t.hour()>hour()) return true; else if(t.hour()<hour()) return false;
    if(t.minute()>minute()) return true; else if(t.minute()<minute()) return false;
    if(t.second()>second()) return true; else if(t.second()<second()) return false;
    if(t.m_ms>m_ms) return true; else if(t.m_ms<m_ms) return false;
    return true;
}

bool MTime::operator== ( const MTime & t ) const
{
    return (t.hour() == hour() && t.minute() == minute() && t.second() == second() && t.m_ms == m_ms );
}

bool MTime::operator>  ( const MTime & t ) const
{
    if(t.hour()<hour()) return true; else if(t.hour()>hour()) return false;
    if(t.minute()<minute()) return true; else if(t.minute()>minute()) return false;
    if(t.second()<second()) return true; else if(t.second()>second()) return false;
    if(t.m_ms<m_ms) return true; else if(t.m_ms>m_ms) return false;
    return false;
}

bool MTime::operator>= ( const MTime & t ) const
{
    if(t.hour()<hour()) return true; else if(t.hour()>hour()) return false;
    if(t.minute()<minute()) return true; else if(t.minute()>minute()) return false;
    if(t.second()<second()) return true; else if(t.second()>second()) return false;
    if(t.m_ms<m_ms) return true; else if(t.m_ms>m_ms) return false;
    return true;
}


